package show.me.the.money.servlet;

import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;

import show.me.the.money.accredit.User;
import show.me.the.money.accredit.UsersController;
import show.me.the.money.service.core.Service;


@SuppressWarnings({"unchecked"})
public class FileUploader extends HttpServlet {
	
	private static final long serialVersionUID = 1L;
	private static Log logger = LogFactory.getLog(FileUploader.class);
	
	private static final String DIR_TYPE = "dirType";
	private static final String FILE_NAME = "fileName";
	private static long fileUploadMaxSize;
	private static String tempDirectory;
	private static ObjectMapper jsonMapper =  new ObjectMapper();
	private static ServletFileUpload fileUpload;
	
	@Override
	public void init() throws ServletException {
		String limitSize = this.getServletConfig().getInitParameter("fileUploadMaxSize");
		if(StringUtils.isEmpty(limitSize)){
			limitSize = "5M";
		}
		fileUploadMaxSize = getByteSizeFromString(limitSize);
		String tempPath = this.getServletConfig().getInitParameter("tempDirectory");
		if(StringUtils.isEmpty(tempPath)){
			tempPath = "resources/temp";
		}
		tempDirectory = getServletContext().getRealPath(tempPath);
		DiskFileItemFactory factory = new DiskFileItemFactory();
		factory.setSizeThreshold(1024*1024);
		fileUpload = new ServletFileUpload(factory);
		fileUpload.setSizeMax(1024*1024*20);
		fileUpload.setFileSizeMax(fileUploadMaxSize);
		
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doPost(req, resp);
		
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		int code = 200;
		String msg = "Success";
		HashMap<String,Object> res = new HashMap<String,Object>();
		User user = getUser(req);
		if(user == null){
			logger.fatal("user not logon");
			code = 401;
			msg = "UserNotLogon";
		}else{
			HashMap<String,Object> rec = startUpload(req);
			if(rec.size()>0){
				code = (Integer)rec.get(Service.RES_CODE);
				msg = (String)rec.get(Service.RES_MESSAGE);
			}
		}
		res.put(Service.RES_CODE, code);
		res.put(Service.RES_MESSAGE, msg);
		writeToResponse(resp, res);		
	}
	
	private HashMap<String,Object> startUpload(HttpServletRequest req){
		HashMap<String,Object> rec = new HashMap<String,Object>();
		String path = tempDirectory;
		String fileName = "";
		try {
			List<FileItem> fis = fileUpload.parseRequest(req);
			for(FileItem fi : fis){
				if(fi.isFormField()){
					String filed = fi.getFieldName();
					if(DIR_TYPE.equals(filed)){
						String tempPath = this.getServletConfig().getInitParameter(fi.getString());
						if(!StringUtils.isEmpty(tempPath)){
							path = getServletContext().getRealPath(tempPath);
						}
					}
					if(FILE_NAME.equals(filed)){
						fileName = fi.getString();
					}
				}else{
					String name = fi.getName();
					if(StringUtils.isEmpty(fileName)){
						fileName = name.substring(name.lastIndexOf("\\")+1);
					}
					checkDir(path);
					path = path + File.separator + fileName;
					File file = new File(path);
					fi.write(file);	
				}
			}
			
		} catch (Exception e) {
			rec.put(Service.RES_CODE, 403);
			rec.put(Service.RES_MESSAGE, e.getMessage());
			logger.fatal("exception: "+e.getMessage());			
		}
		return rec;
	}
	
	private void writeToResponse(HttpServletResponse response,HashMap<String,Object> res) throws IOException{
		response.setContentType("text/html;charset=UTF-8");
		OutputStreamWriter out = new OutputStreamWriter(response.getOutputStream(),"utf-8");
		jsonMapper.writeValue(out, res);
	}
	
	private long getByteSizeFromString(String s){
		long size = 0l;
		String unit = "m";
		Pattern p = Pattern.compile("(\\d+)([mMkK])");
		Matcher m = p.matcher(s);
		
		if(!m.find()){
			return size;
		}
		if(m.groupCount() == 2){
			size = Long.parseLong(m.group(1));
			unit = m.group(2).toLowerCase();
			
			if(unit.equals("m")){
				size *= 1024 * 1024; 
			}
			if(unit.equals("k")){
				size *= 1024;
			}
		}
		
		return size;
	}
	
	private User getUser(HttpServletRequest request){
		String id = (String)request.getSession().getAttribute("uid");
		if(id == null){
			return null;
		}
		return UsersController.instance().getUser(id);
	}
	
	private void checkDir(String path){
		File f = new File(path);
		if(!f.exists()){
			f.mkdir();
		}
	}

}
